class Member < ActiveRecord::Base

  has_many :attendance_records, :conditions => {:waitlist => false}
  has_many :events, :through => :attendance_records
  has_many :positions
  has_many :announcements

  validates_presence_of :first_name
  validates_presence_of :last_name
  validates_presence_of :username
  validates_presence_of :password

  def full_name
    "#{first_name} #{last_name}"
  end

  def last_first
    "#{last_name}, #{first_name}"
  end

  def self.authenticate(username, password)
    find_by_username_and_password(username, hash_password(password))
  end

  def self.hash_password(password)
    Digest::SHA1.hexdigest(password)
  end

  def self.find_members(filter, sort_by)
    if filter.nil? or filter.empty?
      find :all, :conditions => "members.deleted = false AND (members.status = 'Active' OR members.status = 'Pledge' OR members.status = 'New Active' OR members.status = 'Neophyte' OR members.status = 'Probate' OR members.status = 'Associate')", :order => sort_by.nil? ? "last_name, first_name ASC" : "members.#{sort_by} DESC, last_name ASC"
    elsif filter == "All"
      find :all, :conditions => "members.deleted = false", :order => sort_by.nil? ? "last_name, first_name ASC" : "members.#{sort_by} DESC, last_name ASC"
    else
      find :all, :conditions => {:deleted => false, :status => filter}, :order => sort_by.nil? ? "last_name, first_name ASC" : "members.#{sort_by} DESC, last_name ASC"
    end
  end

  def self.find_birthdays
    find :all, :select => "id, first_name, last_name, birthday, (YEAR(CURDATE())-YEAR(birthday)) - (RIGHT(CURDATE(),5)<RIGHT(birthday,5)) AS age",
         :order => "MONTH(birthday), DAY(birthday), last_name, first_name",
         :conditions => "(DAY(birthday) >= DAY(CURDATE()) AND DAY(birthday)-DAY(CURDATE()) <= 7 AND MONTH(birthday) = MONTH(CURDATE())) OR
                                (DAY(CURDATE())-DAY(birthday) >= 7 AND MONTH(birthday) = 1 AND MONTH(CURDATE()) = 12) OR
                                (DAY(CURDATE())-DAY(birthday) >= 23 AND MONTH(birthday) - MONTH(CURDATE()) = 1) AND status <> 'Alum' AND status <> 'Away From School'"
  end

  #Actives
  def self.active_service_requirement
    24
  end

  def self.active_fellowships_requirement
    8
  end

  def self.active_leaderships_requirement
    10
  end

  def self.active_fundraisers_requirement
    3
  end

  def self.active_meetings_requirement
    20
  end

  def self.active_dues_requirement
    2
  end

  def self.active_trisecs_requirement
    4
  end

  # Pledges
  def self.pledge_service_requirement
    20
  end

  def self.pledge_fellowships_requirement
    6
  end

  def self.pledge_leaderships_requirement
    6
  end

  def self.pledge_fundraisers_requirement
    1
  end

  def self.pledge_meetings_requirement
    19
  end

  def self.pledge_dues_requirement
    2
  end

  def self.pledge_reqs_requirement
    9
  end

  def self.get_adjustment_hours(memberID, eventID)
    record = AttendanceRecord.find(:first, :conditions => {:event_id => "#{eventID}", :member_id => "#{memberID}"})
    if record.adjustment_hours.nil?
      record.adjustment_hours = 0.0
      record.save
    end
    return record.adjustment_hours
  end

  def self.getData(member, semester)
    # this will hold the member's data
    data = {
        "dues" => 0,
        "fellowship" => {"potential" => 0, "actual" => 0},
        "fundraiser" => {"potential" => 0, "actual" => 0},
        "hours" => {"potential" => 0, "actual" => 0},
        "leadership" => {"potential" => 0, "actual" => 0},
        "meeting" => {"potential" => 0, "actual" => 0},
        "percent" => 0,
        "pledge_req" => {"potential" => 0, "actual" => 0},
        "service" => {"potential" => 0, "actual" => 0},
        "trisec" => {"potential" => 0, "actual" => 0},
        "total_hours" => 0,
        "total_required_hours" => 0
    }

    # if the member's data hasn't been changed since the last read, return the stored data
    if (member.up_to_date == true)
      get_stored_data(member, data)
    else
      if member.status == "Active" or member.status == "Probate" or member.status == "Associate" or
          member.status == "Neophyte" or member.status == "New Active" or member.status == "Pledge"

        potential_indy_hours = 0 # accumulate total potential indy hours
        actual_indy_hours = 0 # accumulate total actual indy hours
        penalty = 0 # number of penalty hours
        amount = 0 # amount of missed service events (for pledges only)
        now = Time.now # current time and date

        # get all of the member's events and calculate requirements progress
        memberEvents = member.events.find_all_by_semester_index_and_deleted(semester, false)
        memberEvents.each do |event|
          currentAR = member.attendance_records.find_by_event_id_and_waitlist(event.id, false)
          unless currentAR.nil?
            # add penalty hours if member did not attend a service event
            if currentAR.attended == false and event.approved == true and event.event_type == "Service"
              penalty += event.additional_service_hours / 2
              if member.status == "Pledge"
                amount += 1
              end
            elsif currentAR.attended == true
              # null check
              if currentAR.adjustment_hours.nil?
                currentAR.adjustment_hours = 0.0
                currentAR.save
              end

              # calculate the data!
              if event.event_type != "Indy Hours"
                handle_attendance_record(member, data, event, currentAR, now)
              else
                potential_indy_hours += event.hours + currentAR.adjustment_hours
                if event.approved == true and event.date < now
                  actual_indy_hours += event.hours + currentAR.adjustment_hours
                end
              end
            end
          end
        end

        # members only get a certain amount of indy hours that count toward total hours
        if member.status == "Active" or member.status == "New Active" or
            member.status == "Probate" or member.status == "Neophyte" or member.status == "Associate"
          if potential_indy_hours > 10
            data["service"]["potential"] += 10
          else
            data["service"]["potential"] += potential_indy_hours
          end
          if actual_indy_hours > 10
            data["service"]["actual"] += 10
          else
            data["service"]["actual"] += actual_indy_hours
          end
        elsif member.status == "Pledge"
          if potential_indy_hours > 6
            data["service"]["potential"] += 6
          else
            data["service"]["potential"] += potential_indy_hours
          end
          if actual_indy_hours > 6
            data["service"]["actual"] += 6
          else
            data["service"]["actual"] += actual_indy_hours
          end
        end

        data["total_required_hours"] = calculate_total_hours(member, penalty, amount)

        data["percent"] = percent_done(member, data)

        set_stored_data(member, data)

        office = member.positions.find_by_semester_index(semester)
        member.office = !office.nil? ? Position.getPosition(office.position) : nil

        member.up_to_date = true
        member.save
      end
    end

    return data
  end

  def self.get_stored_data(member, data)
    data["service"]["potential"] = member.stored_potential_service_hours
    data["fellowship"]["potential"] = member.stored_potential_fellowships
    data["leadership"]["potential"] = member.stored_potential_leaderships
    data["fundraiser"]["potential"] = member.stored_potential_fundraisers
    data["meeting"]["potential"] = member.stored_potential_active_meetings
    data["pledge_req"]["potential"] = member.stored_potential_pledge_reqs
    data["trisec"]["potential"] = member.stored_potential_trisecs
    data["percent"] = member.stored_percent_done
    data["service"]["actual"] = member.stored_service_hours
    data["fellowship"]["actual"] = member.stored_fellowships
    data["leadership"]["actual"] = member.stored_leaderships
    data["fundraiser"]["actual"] = member.stored_fundraisers
    data["dues"] = member.stored_dues
    data["meeting"]["actual"] = member.stored_active_meetings
    data["total_required_hours"] = member.stored_total_hours
    data["pledge_req"]["actual"] = member.stored_pledge_reqs
    data["trisec"]["actual"] = member.stored_trisecs
  end

  def self.set_stored_data(member, data)
    member.stored_potential_service_hours = data["service"]["potential"]
    member.stored_potential_fellowships = data["fellowship"]["potential"]
    member.stored_potential_leaderships = data["leadership"]["potential"]
    member.stored_potential_fundraisers = data["fundraiser"]["potential"]
    member.stored_potential_active_meetings = data["meeting"]["potential"]
    member.stored_potential_pledge_reqs = data["pledge_req"]["potential"]
    member.stored_potential_trisecs = data["trisec"]["potential"]
    member.stored_percent_done = data["percent"]
    member.stored_service_hours = data["service"]["actual"]
    member.stored_fellowships = data["fellowship"]["actual"]
    member.stored_leaderships = data["leadership"]["actual"]
    member.stored_fundraisers = data["fundraiser"]["actual"]
    member.stored_dues = data["dues"]
    member.stored_active_meetings = data["meeting"]["actual"]
    member.stored_total_hours = data["total_required_hours"]
    member.stored_pledge_reqs = data["pledge_req"]["actual"]
    member.stored_trisecs = data["trisec"]["actual"]
  end

  def self.handle_attendance_record(member, data, event, currentAR, now)
    data["service"]["potential"] += event.additional_service_hours + (event.event_type == "Service" ? currentAR.adjustment_hours : 0)
    data["fellowship"]["potential"] += event.additional_fellowships
    data["leadership"]["potential"] += event.additional_leaderships
    data["fundraiser"]["potential"] += event.additional_fundraisers
    data["meeting"]["potential"] += event.additional_active_meetings
    data["trisec"]["potential"] += event.additional_trisecs
    if event.approved == true and event.date < now
      data["service"]["actual"] += event.additional_service_hours + (event.event_type == "Service" ? currentAR.adjustment_hours : 0)
      data["fellowship"]["actual"] += event.additional_fellowships
      data["leadership"]["actual"] += event.additional_leaderships
      data["fundraiser"]["actual"] += event.additional_fundraisers
      data["meeting"]["actual"] += event.additional_active_meetings
      data["trisec"]["actual"] += event.additional_trisecs
    end

    # add special situations
    if event.event_type == "Service" or event.event_type == "Fellowship" or event.event_type == "Leadership" or event.event_type == "Fundraiser" or event.event_type == "Tri-Sectionals"
      if event.mic_id == member.id
        data["leadership"]["potential"] += 1
        if event.approved == true and event.date < now
          data["leadership"]["actual"] += 1
        end
      end
      if currentAR.driver == true
        data["service"]["potential"] += 0.5
        if event.approved == true and event.date < now
          data["service"]["actual"] += 0.5
        end
      end
    elsif event.event_type == "Office Hour"
      data["meeting"]["potential"] += currentAR.adjustment_hours
      if event.approved == true and event.date < now
        data["meeting"]["actual"] += currentAR.adjustment_hours
      end
    elsif event.event_type == "Pledge Req" and member.status == "Pledge"
      data["pledge_req"]["potential"] += 1
      if event.approved == true and event.date < now
        data["pledge_req"]["actual"] += 1
      end
    elsif event.event_type == "Dues"
      data["dues"] += 1
    elsif event.event_type == "Dues (late)"
      data["dues"] += 1
    end
  end

  def self.percent_done(member, data)
    if member.status == "Active" or member.status == "New Active" or member.status == "Associate" or member.status == "Probate" or member.status == "Neophyte"
      done = data["service"]["actual"] > data["total_required_hours"] ? data["total_required_hours"] : data["service"]["actual"]
      done += data["leadership"]["actual"] > active_leaderships_requirement ? active_leaderships_requirement : data["leadership"]["actual"]
      done += data["fellowship"]["actual"] > active_fellowships_requirement ? active_fellowships_requirement : data["fellowship"]["actual"]
      done += data["fundraiser"]["actual"] > active_fundraisers_requirement ? active_fundraisers_requirement : data["fundraiser"]["actual"]
      done += data["meeting"]["actual"] > active_meetings_requirement ? active_meetings_requirement : data["meeting"]["actual"]
      done += data["trisec"]["actual"] > active_trisecs_requirement ? active_trisecs_requirement : data["trisec"]["actual"]
      done += data["dues"] > active_dues_requirement ? active_dues_requirement : data["dues"]
      out_of = data["total_required_hours"] + active_leaderships_requirement + active_fellowships_requirement +
          active_fundraisers_requirement + active_meetings_requirement + active_trisecs_requirement + active_dues_requirement
    elsif member.status == "Pledge"
      done = data["service"]["actual"] > data["total_required_hours"] ? data["total_required_hours"] : data["service"]["actual"]
      done += data["leadership"]["actual"] > pledge_leaderships_requirement ? pledge_leaderships_requirement : data["leadership"]["actual"]
      done += data["fellowship"]["actual"] > pledge_fellowships_requirement ? pledge_fellowships_requirement : data["fellowship"]["actual"]
      done += data["fundraiser"]["actual"] > pledge_fundraisers_requirement ? pledge_fundraisers_requirement : data["fundraiser"]["actual"]
      done += data["meeting"]["actual"] > pledge_meetings_requirement ? pledge_meetings_requirement : data["meeting"]["actual"]
      done += data["dues"] > pledge_dues_requirement ? pledge_dues_requirement : data["dues"]
      done += data["pledge_req"]["actual"] > pledge_reqs_requirement ? pledge_reqs_requirement : data["pledge_req"]["actual"]
      out_of = data["total_required_hours"] + pledge_leaderships_requirement + pledge_fellowships_requirement +
          pledge_fundraisers_requirement + pledge_meetings_requirement + pledge_dues_requirement + pledge_reqs_requirement
    else
      done = 0
      out_of = 1
    end
    return (done / out_of * 100).to_i
  end

  def self.calculate_total_hours(member, penalty, amount)
    memberTotalHours = 0
    if member.status == "Active" or member.status == "New Active" or member.status == "Associate" or member.status == "Probate" or member.status == "Neophyte"
      memberTotalHours = active_service_requirement + penalty
    elsif member.status == "Pledge"
      memberTotalHours = pledge_service_requirement + (amount > 1 ? penalty : 0)
    end
  end

  def self.get_committee(member, semester)
    member.events.find_by_semester_index_and_event_type_and_deleted(semester, "Committee", false)
  end

  def self.get_quorum(member)
    dataReturn = getData(member, Event.getCurrentSemester)
#    return dataReturn[9] >= 75 ? "Yes" : "No"
    eligible = "Yes"
    dataReturn[10] < dataReturn[18] ? eligible = "No" : nil
    dataReturn[11] < Member.active_fellowships_requirement ? eligible = "No" : nil
    dataReturn[12] < Member.active_leaderships_requirement ? eligible = "No" : nil
    dataReturn[13] < Member.active_fundraisers_requirement ? eligible = "No" : nil
    dataReturn[14] < Member.active_office_hours_requirement ? eligible = "No" : nil
    dataReturn[15] < 1 ? eligible = "No" : nil
    dataReturn[16] < Member.active_dues_requirement ? eligible = "No" : nil
    dataReturn[23] < dataReturn[22] ? eligible = "No" : nil
    return eligible
#    total = dataReturn[10] + dataReturn[11] + dataReturn[12] + dataReturn[13] + dataReturn[14] + dataReturn[16]
#    if total >= 10
#      return "Yes"
#    else
#      return "No"
#    end
  end

  # Calculate the member's total career service hours including indy hours
  def self.get_career_hours(member)
    total = 0
    memberEvents = member.events.find_all_by_deleted_and_approved(false, true)

    memberEvents.each do |event|
      currentAR = member.attendance_records.find_by_event_id_and_waitlist_and_deleted_and_attended(event.id, false, false, true)
      unless currentAR.nil?
        if event.date < Time.now
          if event.event_type == "Service" or event.event_type == "Indy Hours"
            if event.event_type == "Indy Hours" or event.semester_index <= 4 # the way hours were counted was different back then
              total += event.hours
            end
            if !currentAR.adjustment_hours.nil?
              total += currentAR.adjustment_hours
            end
          end
          total += event.additional_service_hours
        end
      end
    end

    return total
  end

  #service, fellowship, leadership
  def self.get_year_hours(members)
    dataReturn = Array.new(3, 0)

    members.each_with_index do |member, index|
      memberEvents = member.events.find_all_by_deleted(false, :conditions => "semester_index = #{Event.getCurrentSemester} OR semester_index = #{Event.getCurrentSemester - 1}")
      memberEvents.each do |event|
        currentAR = member.attendance_records.find_by_event_id_and_waitlist_and_deleted(event.id, false, false)
        unless currentAR.nil?
          if currentAR.attended == true and event.approved == true and event.date < Time.now
            if event.event_type == "Service" or event.event_type == "Indy Hours"
              dataReturn[0] += event.hours
              if !currentAR.adjustment_hours.nil?
                dataReturn[0] += currentAR.adjustment_hours
              end
            elsif event.event_type == "Leadership"
              dataReturn[2] += 1
            elsif event.event_type == "Fellowship"
              dataReturn[1] += 1
            end
            dataReturn[0] += event.additional_service_hours
            dataReturn[1] += event.additional_fellowships
            dataReturn[2] += event.additional_leaderships
          end
        end
      end
    end

    return dataReturn
  end

end
